<!DOCTYPE html>
<html>
<head>
  <title>Web File Transfer</title>
  <style>
    body {
      background: linear-gradient(to bottom, #003366, #000000); /* 渐变背景 */
      color: #eee;
      font-family: 'Orbitron', sans-serif; /* 科技感字体 */
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: 100vh;
      margin: 0;
      overflow: hidden; /* 隐藏滚动条 */
    }

    h1 {
      color: #00a0d2;
      margin-bottom: 30px; /* 增加标题下边距 */
      font-size: 2.5em; /* 增大标题字体 */
    }

    #users {
      list-style: none;
      padding: 0;
      margin-bottom: 30px;
      width: 350px; /* 增加列表宽度 */
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5); /* 添加阴影 */
      border-radius: 15px; /* 增加圆角 */
      overflow: hidden; /* 隐藏溢出内容 */
    }

    #users li {
      background-color: #333;
      border: none; /* 移除边框 */
      padding: 15px 20px; /* 增加内边距 */
      margin-bottom: 0; /* 移除外边距 */
      cursor: pointer;
      transition: all 0.3s ease; /* 平滑过渡效果 */
      border-radius: 0; /* 移除圆角 */
      display: flex; /* 使用 Flexbox 布局 */
      align-items: center; /* 垂直居中 */
    }

    #users li:first-child {
      border-top-left-radius: 15px; /* 左上角圆角 */
      border-top-right-radius: 15px; /* 右上角圆角 */
    }

    #users li:last-child {
      border-bottom-left-radius: 15px; /* 左下角圆角 */
      border-bottom-right-radius: 15px; /* 右下角圆角 */
    }

    #users li:hover {
      background-color: #00a0d2;
      transform: scale(1.05); /* 放大效果 */
      box-shadow: 0 2px 5px rgba(0, 160, 210, 0.5); /* 悬停阴影 */
    }

    #users li.selected {
      background-color: #0078a8;
    }

    #fileInput {
      margin-bottom: 20px;
    }

    #sendFileButton {
      background: linear-gradient(to right, #00a0d2, #0078a8); /* 渐变背景 */
      color: #fff;
      border: none;
      padding: 15px 30px; /* 增加内边距 */
      cursor: pointer;
      transition: all 0.3s ease;
      border-radius: 25px; /* 大圆角 */
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
      font-family: 'Orbitron', sans-serif;
    }

    #sendFileButton:hover {
      background: linear-gradient(to right, #0078a8, #005070);
      box-shadow: 0 2px 5px rgba(0, 160, 210, 0.5);
      transform: translateY(-2px); /* 上浮效果 */
    }

    #sendFileButton:disabled {
      background: #666;
      cursor: default;
      box-shadow: none;
      transform: none;
    }

    #progressBarContainer {
      width: 350px;
      height: 10px; /* 减小高度 */
      background-color: #333;
      border: none; /* 移除边框 */
      margin-top: 30px;
      border-radius: 25px; /* 大圆角 */
      overflow: hidden;
      display: none;
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
    }

    #progressBar {
      width: 0%;
      height: 100%;
      background-color: #00d26a; /* 鲜艳的绿色 */
      transition: width 0.5s ease; /* 平滑过渡 */
    }
  </style>
</head>
<body>
  <h1>在线用户:</h1>
  <ul id="users"></ul>
  <input type="file" id="fileInput" />
  <button id="sendFileButton" disabled>Send File</button>
  <div id="progressBarContainer">
    <div id="progressBar"></div>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/simple-peer@9.11.1/simplepeer.min.js"></script>
  <script>
    const socket = io();
    let username = null;
    while (!username) {
      username = prompt("请输入你的名字：");
    }
    socket.emit('join', username);

    const usersList = document.getElementById('users');
    const fileInput = document.getElementById('fileInput');
    const sendFileButton = document.getElementById('sendFileButton');
    let selectedUsers = [];
    let fileToSend = null;

    // 更新用户列表
    socket.on('updateUsers', (users) => {
      usersList.innerHTML = '';
      users.filter(user => user !== username).forEach(user => {
        const li = document.createElement('li');
        li.textContent = user;
        li.addEventListener('click', () => {
          if (li.classList.contains('selected')) {
            li.classList.remove('selected');
            selectedUsers = selectedUsers.filter(u => u !== user);
          } else {
            li.classList.add('selected');
            selectedUsers.push(user);
          }
          sendFileButton.disabled = selectedUsers.length === 0;
          console.log(`已选择的用户：${selectedUsers}`);
        });
        usersList.appendChild(li);
      });
    });

    // 文件选择事件
    fileInput.addEventListener('change', (event) => {
      fileToSend = event.target.files[0];
      if (fileToSend) {
        console.log(`已选择的文件：${fileToSend.name}, Size: ${fileToSend.size} bytes`);
      }
    });

    // 发送文件按钮点击事件
    sendFileButton.addEventListener('click', () => {
      if (selectedUsers.length > 0 && fileToSend) {
        selectedUsers.forEach(user => {
          socket.emit('requestFileTransfer', {
            to: user,
            file: {
              name: fileToSend.name,
              size: fileToSend.size,
              type: fileToSend.type
            }
          });
        });
      }
    });

    // 文件传输请求被接受
    socket.on('transferRequestAccepted', (data) => {
      console.log(`File transfer request to ${data.to} accepted`);
      const peer = new SimplePeer({ initiator: true, trickle: false });
      peers[data.to] = peer;

      peer.on('signal', (signalData) => {
        socket.emit('signal', {
          to: data.to,
          signal: signalData
        });
      });

      peer.on('connect', () => {
        console.log(`Data channel connected to ${data.to}`);
        sendFile(peer, fileToSend);
      });
    });

    // 文件传输请求被拒绝
    socket.on('transferRequestRejected', (data) => {
      console.log(`File transfer request to ${data.to} rejected`);
    });

    // 错误处理
    socket.on('fileTransferError', (data) => {
      console.error(`File transfer error: ${data.message}`);
    });

    // 监听文件传输请求
    socket.on('fileTransferRequest', (data) => {
      const accept = confirm(`User ${data.from} wants to send you a file: ${data.file.name} (${data.file.size} bytes). Accept?`);
      socket.emit('respondToTransferRequest', {
        from: data.from,
        response: accept ? 'accept' : 'reject'
      });
      if (accept) {
        totalFileSize = data.file.size;
        fileName = data.file.name;
      }
    });

    // 存储所有对等连接
    const peers = {};

    // 接收文件
    socket.on('signal', (data) => {
      let peer = peers[data.from];
      if (!peer) {
        peer = new SimplePeer({ initiator: false, trickle: false });
        peers[data.from] = peer;

        peer.on('signal', (signalData) => {
          socket.emit('signal', {
            to: data.from,
            signal: signalData
          });
        });

        peer.on('connect', () => {
          console.log(`Data channel connected from ${data.from}`);
        });

        peer.on('data', (data) => {
          receiveFile(data);
        });
      }
      peer.signal(data.signal);
    });

    // 更新进度条的函数
    function updateProgressBar(percentage) {
      const progressBar = document.getElementById('progressBar');
      const progressBarContainer = document.getElementById('progressBarContainer');
      progressBarContainer.style.display = 'block';
      progressBar.style.width = percentage + '%';
    }

    // 发送文件 (修改后的 sendFile 函数)
    function sendFile(peer, file) {
      const chunkSize = 16 * 1024; // 16KB
      const reader = new FileReader();
      let offset = 0;

      reader.onload = function() {
        const arrayBuffer = reader.result;
        for (let i = 0; i < arrayBuffer.byteLength; i += chunkSize) {
          const chunk = arrayBuffer.slice(i, i + chunkSize);
          console.log('Sending chunk of type:', typeof chunk, chunk);
          peer.send(chunk);
          offset += chunk.byteLength;
          // 更新进度条
          updateProgressBar(Math.round((offset / file.size) * 100));
        }
      };

      reader.onerror = function(error) {
        console.error('Error reading file:', error);
      };

      reader.readAsArrayBuffer(file);
    }

    // 接收文件 (修改后的 receiveFile 函数)
    let receivedBuffers = [];
    let totalFileSize = 0;
    let receivedFileSize = 0;
    let fileName = null;

    function receiveFile(data) {
      console.log('Received data:', data);
      if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
        const buffer = data instanceof Uint8Array ? data.buffer : data;
        receivedBuffers.push(buffer);
        receivedFileSize += buffer.byteLength;

        // 更新进度条
        updateProgressBar(Math.round((receivedFileSize / totalFileSize) * 100));

        if (receivedFileSize === totalFileSize) {
          const blob = new Blob(receivedBuffers);
          downloadFile(blob, fileName);
          receivedBuffers = [];
          receivedFileSize = 0;
          totalFileSize = 0;
          fileName = null;
          // 重置进度条
          updateProgressBar(0);
          document.getElementById('progressBarContainer').style.display = 'none';
        }
      } else if (typeof data === 'string') {
        fileName = data;
      } else {
        console.warn('Received data of unsupported type:', typeof data, data);
      }
    }

    async function downloadFile(blob, fileName) {
      if (window.showSaveFilePicker) {
        try {
          // 使用 File System Access API
          const handle = await window.showSaveFilePicker({
            suggestedName: fileName || 'received_file',
          });
     
          const writable = await handle.createWritable();
          await writable.write(blob);
          await writable.close();
     
          console.log('File saved successfully via File System Access API');
        } catch (err) {
          console.error('Error saving file via File System Access API:', err);
          downloadFileFallback(blob, fileName); // 回退到传统下载方式
        }
      } else {
        downloadFileFallback(blob, fileName); // 回退到传统下载方式
      }
    }
     
    function downloadFileFallback(blob, fileName) {
      // 传统下载方式
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = fileName || 'received_file';
      a.style.display = 'none';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
      console.log('File downloaded via traditional method');
    }
  </script>
</body>
</html> 